#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
统一日志服务 - 支持所有模块
"""

from datetime import datetime
import json
import enum
import logging
from backend.config.config_manager import ConfigManager

class UnifiedLogAction(enum.Enum):
    """统一日志操作类型枚举"""
    CREATE = "CREATE"
    UPDATE = "UPDATE"
    DELETE = "DELETE"
    RESTORE = "RESTORE"

class BaseLogService:
    """统一日志服务基类"""
    
    def __init__(self):
        self.config_manager = ConfigManager()
        self.log_config = self.config_manager.get_unified_log_config()
        self.display_config = self.config_manager.get_log_display_formats()
    
    def format_log_data(self, record_data, action, operator='系统', ip_address=None, operation_desc=None):
        """格式化日志数据 - 统一的日志数据处理"""
        return {
            'action': action.value if isinstance(action, UnifiedLogAction) else action,
            'operator': operator,
            'operation_time': datetime.now(),
            'operation_desc': operation_desc or self._generate_operation_desc(action, record_data),
            'ip_address': ip_address,
            'created_at': datetime.now()
        }
    
    def _generate_operation_desc(self, action, record_data):
        """生成标准化的操作描述"""
        action_config = self.log_config['action_types'].get(action.value if isinstance(action, UnifiedLogAction) else action, {})
        action_label = action_config.get('label', action)
        
        # 根据记录类型生成描述
        if 'measure_date' in record_data:
            return f"{action_label}视力记录 - 测量日期: {record_data.get('measure_date')}"
        elif 'date' in record_data:
            return f"{action_label}干预记录 - 日期: {record_data.get('date')}"
        elif 'followup_date' in record_data:
            return f"{action_label}随访记录 - 日期: {record_data.get('followup_date')}"
        else:
            return f"{action_label}记录"
    
    def serialize_content(self, content):
        """序列化内容为JSON字符串"""
        try:
            if hasattr(content, 'to_dict'):
                return json.dumps(content.to_dict(), ensure_ascii=False, default=str)
            elif isinstance(content, dict):
                return json.dumps(content, ensure_ascii=False, default=str)
            else:
                return str(content)
        except Exception as e:
            print(f"序列化内容失败: {e}")
            return str(content)
    
    def format_display_time(self, operation_time):
        """格式化显示时间"""
        if not operation_time:
            return ""
        time_format = self.display_config.get('time_format', '%Y-%m-%d %H:%M:%S')
        return operation_time.strftime(time_format)
    
    def get_action_display_info(self, action):
        """获取操作类型显示信息"""
        # ✅修复：确保action_str始终是字符串，兼容字符串和枚举类型
        if hasattr(action, 'value'):
            action_str = action.value
        else:
            action_str = str(action)
        
        # 从配置中获取显示信息
        display_info = self.log_config['action_types'].get(action_str, {
            'label': action_str,  # 确保label是字符串
            'color': 'secondary',
            'icon': 'circle'
        })
        
        # ✅确保返回的字典中所有值都是可序列化的
        return {
            'label': str(display_info.get('label', action_str)),
            'color': str(display_info.get('color', 'secondary')),
            'icon': str(display_info.get('icon', 'circle'))
        }
    
    # ✅新增：统一日志API响应格式
    def format_log_response(self, logs, config=None):
        """统一格式化日志API响应"""
        logs_data = []
        for log in logs:
            try:
                # 使用to_dict()确保序列化
                log_dict = log.to_dict()
                # 补充action_display字段
                log_dict['action_display'] = self.get_action_display_info(log.action) if hasattr(log, 'action') and log.action else None
                logs_data.append(log_dict)
            except Exception as e:
                print(f"Error processing log {getattr(log, 'id', 'unknown')}: {e}")
                continue
        
        return {
            'success': True,
            'data': logs_data,
            'config': config or self.log_config,
            'message': f'成功获取日志，共{len(logs_data)}条'
        }

    # ✅新增：统一日志查询API处理
    def get_record_logs(self, LogModel, record_id, order_by_field='created_at', config=None):
        """统一的单条记录日志查询处理"""
        try:
            if not record_id:
                return {'success': False, 'message': '缺少记录ID参数'}, 400
            
            # 查询指定记录的所有日志
            logs = LogModel.query.filter_by(record_id=record_id)\
                                .order_by(getattr(LogModel, order_by_field).desc())\
                                .all()
            
            # 使用统一格式化响应
            return self.format_log_response(logs, config), 200
            
        except Exception as e:
            print(f"Error in get_record_logs: {e}")
            import traceback
            traceback.print_exc()
            return {'success': False, 'message': f'获取日志失败: {str(e)}'}, 500
    
    def get_student_all_logs(self, LogModel, student_id, order_by_field='created_at', config=None, student_name=None):
        """统一的学生所有日志查询处理"""
        try:
            if not student_id:
                return {'success': False, 'message': '缺少学生ID参数'}, 400
            
            # 查询该学生的所有日志
            logs = LogModel.query.filter_by(student_id=student_id)\
                                .order_by(getattr(LogModel, order_by_field).desc())\
                                .all()
            
            # 使用统一格式化响应
            response = self.format_log_response(logs, config)
            if student_name:
                response['message'] = f'成功获取学生 {student_name} 的所有操作日志，共{len(response["data"])}条'
            else:
                response['message'] = f'成功获取学生的所有操作日志，共{len(response["data"])}条'
            return response, 200
            
        except Exception as e:
            print(f"Error in get_student_all_logs: {e}")
            import traceback
            traceback.print_exc()
            return {'success': False, 'message': f'获取日志失败: {str(e)}'}, 500
    
    # ✅新增：统一日志配置API
    def get_log_config_response(self):
        """获取日志前端配置的统一响应"""
        try:
            frontend_config = self.config_manager.get_log_frontend_config()
            return {
                'success': True,
                'config': {
                    'action_types': self.log_config['action_types'],
                    'display_formats': self.log_config['display_formats'],
                    'frontend_config': frontend_config
                }
            }, 200
        except Exception as e:
            return {'success': False, 'message': str(e)}, 500
    
    # ✅新增：统一恢复功能
    def restore_record(self, LogModel, RecordModel, log_id, operator='系统', ip_address=None):
        """统一的记录恢复处理
        
        Args:
            LogModel: 日志模型类 (如VisionRecordLog)
            RecordModel: 记录模型类 (如VisionRecord)
            log_id: 要恢复的日志ID
            operator: 操作人
            ip_address: IP地址
            
        Returns:
            (response_dict, status_code)
        """
        try:
            from backend.infrastructure.database import db
            import json
            
            # 查询日志记录
            from backend.infrastructure.database import db
            log = db.session.get(LogModel, log_id)
            if not log:
                return {'success': False, 'message': '日志记录不存在'}, 404
            
            # ✅ 修复：安全获取action字符串值，兼容字符串和枚举类型
            if hasattr(log.action, 'value'):
                action_str = log.action.value
            else:
                action_str = str(log.action)
            
            print(f"🔄 统一恢复服务: 处理{action_str}类型日志")
            
            # ✅ 修复：根据日志模型类型获取正确的记录ID字段
            if hasattr(log, 'target_id'):
                record_id = log.target_id  # SystemLog使用target_id
            elif hasattr(log, 'record_id'):
                record_id = log.record_id  # 其他日志模型使用record_id
            else:
                return {'success': False, 'message': '日志记录缺少记录ID字段'}, 400
            
            if action_str == 'CREATE' or action_str == 'create':
                # CREATE日志恢复 = 删除记录
                from backend.infrastructure.database import db
                record = db.session.get(RecordModel, record_id)
                if not record:
                    return {'success': False, 'message': '原记录已不存在，无法撤销创建操作'}, 404
                
                # 记录删除前状态
                before_data = record.to_dict()
                
                # 记录删除操作日志
                delete_log = LogModel.log_delete(
                    record=record,
                    operator=operator,
                    ip_address=ip_address
                )
                if delete_log:
                    db.session.add(delete_log)
                
                # 删除记录
                db.session.delete(record)
                db.session.commit()
                
                return {
                    'success': True,
                    'message': '撤销创建操作成功，记录已删除',
                    'action': 'delete',
                    'record_id': record_id
                }, 200
                
            elif action_str == 'UPDATE' or action_str == 'edit':
                # UPDATE日志恢复 = 恢复到old_content状态
                if not log.old_content:
                    return {'success': False, 'message': 'UPDATE日志中缺少原始内容，无法恢复'}, 400
                
                # 解析原始数据
                try:
                    old_data = json.loads(log.old_content)
                except json.JSONDecodeError:
                    return {'success': False, 'message': '日志数据格式错误'}, 400
                
                # 查询当前记录
                from backend.infrastructure.database import db
                record = db.session.get(RecordModel, record_id)
                if not record:
                    return {'success': False, 'message': '原记录不存在'}, 404
                
                # 记录恢复前状态
                before_data = record.to_dict()
                
                # 检查是否有实际变化
                key_fields = self._get_key_fields_for_model(RecordModel)
                
                # 强制输出到控制台，确保调试信息可见
                import sys
                print(f"🔍 调试信息 - 模型: {RecordModel.__name__}", file=sys.stderr)
                print(f"🔍 调试信息 - 关键字段: {key_fields}", file=sys.stderr)
                print(f"🔍 调试信息 - 历史数据: {old_data}", file=sys.stderr)
                print(f"🔍 调试信息 - 当前数据: {before_data}", file=sys.stderr)
                
                has_changes = False
                changes_detail = []
                
                # 数据标准化函数
                def normalize_value(value):
                    """标准化数据值，消除格式差异"""
                    if value is None:
                        return None
                    if isinstance(value, str):
                        # 去除首尾空格
                        value = value.strip()
                        # 统一空字符串表示
                        if value == '':
                            return None
                    elif isinstance(value, (int, float)):
                        # 统一数字类型
                        return float(value) if isinstance(value, float) else int(value)
                    elif isinstance(value, list):
                        # 列表排序并标准化每个元素
                        return sorted([normalize_value(item) for item in value])
                    elif isinstance(value, dict):
                        # 字典标准化
                        return {k: normalize_value(v) for k, v in sorted(value.items())}
                    return value
                
                for field in key_fields:
                    old_value = old_data.get(field)
                    current_value = before_data.get(field)
                    
                    # 标准化值进行比较
                    normalized_old = normalize_value(old_value)
                    normalized_current = normalize_value(current_value)
                    
                    # 比较标准化后的值
                    is_different = normalized_old != normalized_current
                    
                    print(f"🔍 字段比较 - {field}: 历史={old_value}(标准化:{normalized_old}), 当前={current_value}(标准化:{normalized_current}), 是否不同={is_different}", file=sys.stderr)
                    
                    if is_different:
                        has_changes = True
                        changes_detail.append(f"{field}: {current_value} → {old_value}")
                
                print(f"🔍 调试信息 - 是否有变化: {has_changes}", file=sys.stderr)
                print(f"🔍 调试信息 - 变化详情: {changes_detail}", file=sys.stderr)
                
                if not has_changes:
                    return {
                        'success': False, 
                        'message': '恢复的历史数据与当前数据相同，无需恢复',
                        'details': '选择的历史版本与当前版本数据一致'
                    }, 400
                
                # 应用恢复数据
                self._apply_restore_data(record, old_data)
                
                # 记录恢复操作日志 - 根据模型类型调用正确的方法
                try:
                    # 尝试调用标准的log_restore方法
                    restore_log = LogModel.log_restore(
                        record_id=record.id,
                        old_data=before_data,  # 恢复前状态
                        restored_data=old_data,  # 恢复后状态
                        operator=operator,
                        ip_address=ip_address
                    )
                except TypeError:
                    # 如果参数不匹配，尝试包含student_id的版本
                    restore_log = LogModel.log_restore(
                        record_id=record.id,
                        student_id=record.student_id,
                        old_data=before_data,  # 恢复前状态
                        restored_data=old_data,  # 恢复后状态
                        operator=operator,
                        ip_address=ip_address
                    )
                if restore_log:
                    db.session.add(restore_log)
                
                db.session.commit()
                
                return {
                    'success': True,
                    'message': f'记录恢复成功，共变更{len(changes_detail)}个字段',
                    'action': 'restore',
                    'changes': changes_detail,
                    'data': record.to_dict()
                }, 200
                
            elif action_str == 'DELETE' or action_str == 'delete':
                # DELETE日志恢复 = 重新创建记录
                if not log.old_content:
                    return {'success': False, 'message': '日志中无可恢复的内容'}, 400
                
                # 解析原始数据
                try:
                    old_data = json.loads(log.old_content)
                except json.JSONDecodeError:
                    return {'success': False, 'message': '日志数据格式错误'}, 400
                
                # 创建新记录
                new_record = RecordModel()
                self._apply_restore_data(new_record, old_data)
                
                # 保存新记录
                db.session.add(new_record)
                db.session.flush()  # 获取新记录ID
                
                # 记录恢复操作日志 - 根据模型类型调用正确的方法
                try:
                    # 尝试调用标准的log_restore方法
                    restore_log = LogModel.log_restore(
                        record_id=new_record.id,
                        old_data={},  # 恢复前状态（记录不存在）
                        restored_data=old_data,  # 恢复后状态
                        operator=operator,
                        ip_address=ip_address
                    )
                except TypeError:
                    # 如果参数不匹配，尝试包含student_id的版本
                    restore_log = LogModel.log_restore(
                        record_id=new_record.id,
                        student_id=new_record.student_id,
                        old_data={},  # 恢复前状态（记录不存在）
                        restored_data=old_data,  # 恢复后状态
                        operator=operator,
                        ip_address=ip_address
                    )
                if restore_log:
                    db.session.add(restore_log)
                
                db.session.commit()
                
                return {
                    'success': True,
                    'message': '已删除的记录恢复成功',
                    'data': new_record.to_dict()
                }, 200
                
            elif action_str == 'RESTORE' or action_str == 'restore':
                # RESTORE日志不支持恢复
                return {'success': False, 'message': 'RESTORE日志是恢复操作的记录，不支持再次恢复'}, 400
                
            else:
                return {'success': False, 'message': f'不支持的日志类型: {action_str}'}, 400
                
        except Exception as e:
            db.session.rollback()
            print(f"❌ 统一恢复服务失败: {e}")
            import traceback
            traceback.print_exc()
            return {'success': False, 'message': str(e)}, 500
    
    def _get_key_fields_for_model(self, RecordModel):
        """根据模型类型获取关键字段列表（完全配置驱动）"""
        model_name = RecordModel.__name__
        return self.config_manager.get_unified_log_module_fields(model_name)
    
    def _apply_restore_data(self, record, data_dict):
        """应用恢复数据到记录对象"""
        # 排除不应该恢复的字段
        exclude_fields = {'id', 'created_at'}
        
        for key, value in data_dict.items():
            if key not in exclude_fields and hasattr(record, key):
                # 特殊处理关系字段
                if key == 'roles' and isinstance(value, list):
                    # 处理用户角色关系
                    try:
                        from backend.models.role import Role
                        from backend.infrastructure.database import db
                        
                        print(f"🔧 处理角色关系恢复: {value}")
                        
                        # 清空当前角色
                        record.roles.clear()
                        
                        # 根据角色名称查找并添加角色对象
                        for role_name in value:
                            role = Role.query.filter_by(name=role_name).first()
                            if role:
                                record.roles.append(role)
                                print(f"✅ 添加角色: {role_name}")
                            else:
                                print(f"⚠️ 警告：角色 '{role_name}' 不存在，跳过")
                        
                        print(f"✅ 角色关系恢复完成，当前角色: {[r.name for r in record.roles]}")
                        continue  # 跳过后续的 setattr
                    except Exception as e:
                        print(f"❌ 恢复角色关系失败: {e}")
                        continue
                
                # 特殊字段处理
                elif key == 'measure_date' and value is not None:
                    if isinstance(value, str):
                        try:
                            from datetime import datetime
                            if 'T' in value:
                                value = datetime.fromisoformat(value.replace('Z', '+00:00')).date()
                            else:
                                value = datetime.strptime(value, '%Y-%m-%d').date()
                        except ValueError:
                            print(f"恢复时日期格式转换失败: {key}={value}")
                            continue
                
                elif key == 'measure_time' and value is not None:
                    if isinstance(value, str):
                        try:
                            from datetime import datetime
                            if len(value) == 8:  # HH:MM:SS
                                value = datetime.strptime(value, '%H:%M:%S').time()
                            elif len(value) == 5:  # HH:MM
                                value = datetime.strptime(value, '%H:%M').time()
                        except ValueError:
                            print(f"恢复时时间格式转换失败: {key}={value}")
                            continue
                
                elif key in ['created_at', 'updated_at'] and value is not None:
                    if isinstance(value, str):
                        try:
                            from datetime import datetime
                            value = datetime.fromisoformat(value.replace('Z', '+00:00'))
                        except ValueError:
                            print(f"恢复时datetime格式转换失败: {key}={value}")
                            continue
                
                # 数据类型转换
                elif value is not None:
                    # 获取字段类型
                    column = getattr(record.__class__, key, None)
                    if column and hasattr(column.property, 'columns'):
                        column_type = column.property.columns[0].type
                        
                        # 根据字段类型转换数据
                        if hasattr(column_type, 'python_type'):
                            try:
                                if column_type.python_type == float and isinstance(value, (int, str)):
                                    value = float(value)
                                elif column_type.python_type == int and isinstance(value, (str, float)):
                                    value = int(value)
                            except (ValueError, TypeError):
                                pass  # 保持原值
                
                # 只有非关系字段才使用 setattr
                if key != 'roles':
                    setattr(record, key, value)



# 实例化服务 - 稍后在类定义完成后实例化
log_service = None

# ==================== 学生档案日志服务扩展 ====================

class StudentArchiveLogService(BaseLogService):
    """学生档案专用日志服务（使用数据库模型）"""
    
    def log_student_operation(self, student_id, action, operation_data, operator='系统', ip_address=None):
        """记录学生档案操作日志到数据库
        
        Args:
            student_id: 学生ID
            action: 操作类型 ('CREATE', 'UPDATE', 'DELETE')
            operation_data: 操作数据
            operator: 操作人
            ip_address: IP地址
        """
        try:
            from backend.models.student_archive_log import StudentArchiveLog, StudentLogAction
            import json
            
            # 根据操作类型调用相应的日志方法
            if action == 'CREATE':
                # 创建操作
                student_data = operation_data.get('operation_data', {})
                extension_data = operation_data.get('extension_data')
                
                result = StudentArchiveLog.log_create(
                    student=DictObj(student_data),  # 转换为对象形式
                    extension_data=extension_data,
                    operator=operator,
                    ip_address=ip_address
                )
                
            elif action == 'UPDATE':
                # 更新操作
                old_data = operation_data.get('original_data', {})
                new_data = operation_data.get('new_data', {})
                updated_fields = {
                    'basic': operation_data.get('updated_basic_fields', []),
                    'extension': operation_data.get('updated_extension_fields', [])
                }
                
                result = StudentArchiveLog.log_update(
                    student_id=student_id,
                    old_data=old_data,
                    new_data=new_data,
                    updated_fields=updated_fields,
                    operator=operator,
                    ip_address=ip_address
                )
                
            elif action == 'DELETE':
                # 删除操作
                student_data = operation_data.get('student_data', {})
                
                result = StudentArchiveLog.log_delete(
                    student_id=student_id,
                    student_data=student_data,
                    operator=operator,
                    ip_address=ip_address
                )
                
            else:
                # 其他操作，使用通用日志记录
                result = self._log_generic_operation(student_id, action, operation_data, operator, ip_address)
            
            # 同时记录到应用日志（作为备份）
            logging.info(f"学生档案操作日志: {action} - 学生ID: {student_id} - 操作人: {operator}")
            
            return result
            
        except Exception as e:
            logging.error(f"记录学生档案日志失败: {e}")
            # 降级到应用日志
            try:
                logging.info(f"学生档案操作日志(降级): {action} - 学生ID: {student_id} - 操作人: {operator}")
                logging.info(f"操作详情(降级): {operation_data}")
                return True
            except:
                return False
    
    def _log_generic_operation(self, student_id, action, operation_data, operator, ip_address):
        """通用操作日志记录"""
        try:
            from backend.models.student_archive_log import StudentArchiveLog, StudentLogAction
            from datetime import datetime
            import json
            
            # 尝试将字符串转换为枚举
            try:
                log_action = StudentLogAction(action.upper())
            except ValueError:
                logging.warning(f"未知的学生档案操作类型: {action}，使用UPDATE作为默认值")
                log_action = StudentLogAction.UPDATE
            
            log = StudentArchiveLog(
                student_id=student_id,
                action=log_action,
                operator=operator,
                operation_time=datetime.now(),
                old_content='{}',
                new_content=json.dumps(operation_data, ensure_ascii=False, default=str),
                operation_desc=f'学生档案操作: {action}',
                ip_address=ip_address,
                module_source='student_archive'
            )
            
            from backend.infrastructure.database import db
            db.session.add(log)
            db.session.commit()
            return True
            
        except Exception as e:
            logging.error(f"通用学生档案日志记录失败: {e}")
            return False
    
    def get_student_logs(self, student_id, limit=50):
        """获取学生操作日志"""
        try:
            from backend.models.student_archive_log import StudentArchiveLog
            return StudentArchiveLog.get_student_logs(student_id, limit)
        except Exception as e:
            logging.error(f"获取学生日志失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'logs': []
            }
    
    def log_restore(self, student_id, operator='系统', operation_desc='恢复学生档案', 
                   restored_from_log_id=None, old_content=None, new_content=None,
                   ip_address=None, user_agent=None):
        """
        记录学生档案恢复操作日志
        
        Args:
            student_id: 学生ID
            operator: 操作人
            operation_desc: 操作描述
            restored_from_log_id: 来源日志ID
            old_content: 恢复前的数据
            new_content: 恢复后的数据
            ip_address: 操作IP
            user_agent: 用户代理
        """
        try:
            from backend.models.student_archive_log import StudentArchiveLog
            
            result = StudentArchiveLog.log_restore(
                student_id=student_id,
                operator=operator,
                operation_desc=operation_desc,
                restored_from_log_id=restored_from_log_id,
                old_content=old_content,
                new_content=new_content,
                ip_address=ip_address,
                user_agent=user_agent
            )
            
            if result.get('success'):
                logging.info(f"学生档案恢复日志记录成功: 学生ID {student_id} - 操作人: {operator}")
            else:
                logging.error(f"学生档案恢复日志记录失败: {result.get('error')}")
            
            return result
            
        except Exception as e:
            logging.error(f"记录学生档案恢复日志服务失败: {e}")
            return {'success': False, 'error': str(e)}

# 辅助类：将字典转换为对象，支持属性访问
class DictObj:
    """字典对象转换器"""
    def __init__(self, data):
        for key, value in data.items():
            setattr(self, key, value)
        # 确保必要的属性存在
        if not hasattr(self, 'id'):
            self.id = data.get('student_id', 0)
        if not hasattr(self, 'name'):
            self.name = data.get('name', '未知')
        if not hasattr(self, 'education_id'):
            self.education_id = data.get('education_id', '未知')

# 统一日志服务类 - 包含所有模块支持
class UnifiedLogService(BaseLogService):
    """统一日志服务 - 支持所有模块"""
    
    def __init__(self):
        super().__init__()
        self.student_service = StudentArchiveLogService()
    
    def log_operation(self, user_id, action, table_name, record_id=None, details=None):
        """通用操作日志记录方法"""
        try:
            from flask import current_app
            current_app.logger.info(f'[LOG] 用户{user_id} 执行{action}操作 - 表:{table_name} ID:{record_id} 详情:{details}')
            # 这里可以根据需要添加数据库记录逻辑
            return True
        except Exception as e:
            from flask import current_app
            current_app.logger.error(f'日志记录失败: {str(e)}')
            return False
    
    def log_student_operation(self, student_id, action, operation_data, operator='系统', ip_address=None):
        """学生档案操作日志接口"""
        return self.student_service.log_student_operation(
            student_id, action, operation_data, operator, ip_address
        )
    
    def get_student_logs(self, student_id, limit=50):
        """获取学生操作日志接口"""
        return self.student_service.get_student_logs(student_id, limit)
    
    def get_student_archive_service(self):
        """获取学生档案日志服务实例"""
        return self.student_service


# 在类定义完成后实例化统一日志服务
log_service = UnifiedLogService()
